"""
NetEase登录系统 - 主程序
支持账号密码登录和钉钉第三方登录
"""
import logging
from contextlib import asynccontextmanager

from fastapi import FastAPI, WebSocket, Request, Response
from fastapi.middleware.cors import CORSMiddleware
from apscheduler.schedulers.asyncio import AsyncIOScheduler
from apscheduler.triggers.interval import IntervalTrigger

from utils.config import config
from utils import JWTUtils
from Views import (
    auth_router, search_router, home_router, qiniu_router, rz_router,
    travel_router, order_router, favorite_router, review_router, 
    recommendation_router, chat_router, qa_router, coze_router, payment_router
)
from Views.home.websocket.ws_service import websocket_endpoint
from Views.home.tasks.ocr_processor import process_batch
from Views.home.tasks.order_tasks import cancel_expired_orders

# 配置日志
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
)

logger = logging.getLogger(__name__)

# 创建调度器
scheduler = AsyncIOScheduler()


@asynccontextmanager
async def lifespan(app: FastAPI):
    """应用生命周期管理"""
    import asyncio
    from concurrent.futures import ThreadPoolExecutor
    from utils.rag_service import get_rag_service
    
    # 启动时
    logger.info("启动定时任务...")
    
    # 创建线程池用于执行同步函数
    executor = ThreadPoolExecutor(max_workers=1)
    
    async def async_process_batch():
        """异步包装同步处理函数"""
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(executor, process_batch)
    
    scheduler.add_job(
        async_process_batch,
        trigger=IntervalTrigger(seconds=5),  # 每5秒执行一次
        id='ocr_processor',
        max_instances=1,
        replace_existing=True
    )
    
    # 添加自动取消超时订单的定时任务
    async def async_cancel_expired_orders():
        """异步包装取消超时订单函数"""
        loop = asyncio.get_event_loop()
        await loop.run_in_executor(executor, cancel_expired_orders)
    
    scheduler.add_job(
        async_cancel_expired_orders,
        trigger=IntervalTrigger(minutes=1),  # 每1分钟执行一次
        id='cancel_expired_orders',
        max_instances=1,
        replace_existing=True
    )
    
    scheduler.start()
    logger.info("定时任务已启动：")
    logger.info("  - OCR处理任务：每5秒处理10个OCR任务")
    logger.info("  - 自动取消超时订单：每1分钟检查一次，取消超过15分钟未支付的订单")
    
    # 检查并自动构建知识库
    try:
        logger.info("检查知识库状态...")
        rag_service = get_rag_service()
        if rag_service.is_knowledge_base_empty():
            logger.info("知识库为空，开始自动构建...")
            loop = asyncio.get_event_loop()
            success = await loop.run_in_executor(executor, rag_service.build_knowledge_base)
            if success:
                logger.info("知识库自动构建成功！")
            else:
                logger.warning("知识库自动构建失败，请检查知识库目录中是否有文件")
        else:
            logger.info("知识库已存在，跳过构建")
    except Exception as e:
        logger.error(f"检查或构建知识库时出错: {e}", exc_info=True)
    
    yield
    
    # 关闭时
    logger.info("关闭定时任务...")
    scheduler.shutdown()
    executor.shutdown(wait=True)


# 创建FastAPI应用
app = FastAPI(
    title=config.APP_NAME,
    version=config.APP_VERSION,
    description="旅游平台系统 - 支持账号密码登录和钉钉第三方登录",
    lifespan=lifespan
)

# 配置CORS中间件
# 使用更宽松的配置解决跨域问题
# 注意：当使用allow_credentials=True时，不能使用allow_origins=["*"]
# 需要明确指定允许的来源，或者在开发环境不使用credentials
app.add_middleware(
    CORSMiddleware,
    allow_origins=[
        "http://localhost:5173",
        "http://127.0.0.1:5173",
        "http://localhost:3000",
        "http://127.0.0.1:3000",
    ],  # 允许的前端来源
    allow_credentials=True,
    allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"],
    allow_headers=["*"],
    expose_headers=["*"],
    max_age=3600,
)

# 全局异常处理器 - 确保错误响应也包含CORS头
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse

@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
    """全局异常处理器，确保所有错误响应都包含CORS头"""
    origin = request.headers.get("origin")
    allowed_origins = [
        "http://localhost:5173",
        "http://127.0.0.1:5173",
        "http://localhost:3000",
        "http://127.0.0.1:3000",
    ]
    
    headers = {}
    if origin in allowed_origins:
        headers = {
            "Access-Control-Allow-Origin": origin,
            "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS, PATCH",
            "Access-Control-Allow-Headers": "*",
            "Access-Control-Allow-Credentials": "true",
        }
    
    logger.error(f"未处理的异常: {exc}", exc_info=True)
    return JSONResponse(
        status_code=500,
        content={"detail": "服务器内部错误", "error": str(exc)},
        headers=headers
    )

@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request: Request, exc: RequestValidationError):
    """请求验证异常处理器"""
    origin = request.headers.get("origin")
    allowed_origins = [
        "http://localhost:5173",
        "http://127.0.0.1:5173",
        "http://localhost:3000",
        "http://127.0.0.1:3000",
    ]
    
    headers = {}
    if origin in allowed_origins:
        headers = {
            "Access-Control-Allow-Origin": origin,
            "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS, PATCH",
            "Access-Control-Allow-Headers": "*",
            "Access-Control-Allow-Credentials": "true",
        }
    
    return JSONResponse(
        status_code=422,
        content={"detail": exc.errors()},
        headers=headers
    )

# 注册路由
app.include_router(auth_router)
app.include_router(search_router)
app.include_router(home_router)
app.include_router(qiniu_router)
app.include_router(rz_router)
app.include_router(travel_router)
app.include_router(order_router)
app.include_router(favorite_router)
app.include_router(review_router)
app.include_router(recommendation_router)  # 推荐系统路由
app.include_router(chat_router)
app.include_router(qa_router)  # 智能问答路由
app.include_router(coze_router)  # 扣子AI路由
app.include_router(payment_router, prefix="/api")  # 支付路由


# WebSocket路由
@app.websocket("/ws/{token}")
async def websocket_route(websocket: WebSocket, token: str):
    """WebSocket路由 - 需要token验证"""
    try:
        payload = JWTUtils.decode_access_token(token)
        if not payload or not payload.get("user_id"):
            await websocket.close(code=1008, reason="认证失败")
            return
        user_id = payload["user_id"]
        await websocket_endpoint(websocket, user_id)
    except Exception as e:
        logger.error(f"WebSocket认证失败: {e}")
        await websocket.close(code=1008, reason="认证失败")


@app.get("/", tags=["根路径"])
async def root():
    """根路径"""
    return {
        "message": "欢迎使用旅游平台系统",
        "version": config.APP_VERSION,
        "features": [
            "账号密码登录",
            "钉钉第三方登录",
            "JWT令牌认证"
        ]
    }


@app.get("/health", tags=["健康检查"])
async def health_check():
    """健康检查接口"""
    return {
        "status": "healthy",
        "app_name": config.APP_NAME,
        "version": config.APP_VERSION
    }


# 处理 OPTIONS 预检请求的通用路由
@app.options("/{full_path:path}")
async def options_handler(full_path: str, request: Request):
    """处理 OPTIONS 预检请求"""
    origin = request.headers.get("origin")
    allowed_origins = [
        "http://localhost:5173",
        "http://127.0.0.1:5173",
        "http://localhost:3000",
        "http://127.0.0.1:3000",
    ]
    
    # 检查origin是否在允许列表中
    if origin in allowed_origins:
        return Response(
            content="OK",
            status_code=200,
            headers={
                "Access-Control-Allow-Origin": origin,
                "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, OPTIONS, PATCH",
                "Access-Control-Allow-Headers": "*",
                "Access-Control-Allow-Credentials": "true",
                "Access-Control-Max-Age": "3600",
            }
        )
    else:
        return Response(status_code=403)

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(
        "main:app",
        host="0.0.0.0",
        port=8000,
        reload=True
    )